<?php

namespace App\Http\Controllers\Laravel\Collection;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class TestController extends Controller
{
    public $collection = array();
    public function __construct()
    {
        //参考http://laravelacademy.org/post/6863.html
        //创建集合
        $this->collection = collect([1,2,3,4]);
    }

    /**
     * 简单返回集合表示的底层数组
     * @return array
     */
    public function myAll(){
        return $this->collection->all();
    }

    /**
     * 返回所有集合项的平均值
     * @return mixed
     */
    public function myAvg(){
        return $this->collection->avg();
    }

    /**
     * 如果集合包含嵌套的数组或对象，
     * 需要指定要使用的键以判定计算哪些值的平均值
     * @return mixed
     */
    public function myAvg2(){
        $books = [
            ['title' => 'One Piece','pages' => 45323],
            ['title' => 'Two Piece','pages' => 25323],
        ];
        return collect($books)->avg('pages');
    }

    /**
     * 将一个集合分割成多个小尺寸的小集合
     * 注:下标不变
     * @return array
     */
    public function myChunk(){
        $chunks = $this->collection->chunk(2);
        var_dump($chunks ->toArray());
        return $chunks ->toArray();
    }

    /**
     * 将一个多维数组集合收缩成一个一维数组
     * @return array
     */
    public function myCollapse(){
        $allCollection = collect([$this->collection,[8,7,5],[2,2,2]]);
        $collapse = $allCollection -> collapse();
        return $collapse->all();
    }

    /**
     * 可以将一个集合的键和另一个数组或集合的值连接起来
     * 注:键值,键名的数量要对应,不然会报错
     * @return static
     */
    public function myCombine(){
        $keyArr = collect(['name','age']);
        $fullArr = $keyArr->combine(['Home','25','100']);
        return $fullArr;
    }

    /**
     * 判断集合是否包含一个给定项
     */
    public function myContains(){
        $collection = collect(['name' => 'hello','age' => 20]);
        $resO = $collection -> contains('name');
        $resT = $collection -> contains('hello');
        $resTh = $collection -> contains('name','hello2');
        $resF = $collection -> contains('name','hello');
        dd($resO,$resT,$resTh,$resF);
    }

    public function myContains2(){
        $collection = collect([
            ['name' => 'hello','age' => 20]
        ]);
        $resO = $collection -> contains('name');
        $resT = $collection -> contains('hello');
        $resTh = $collection -> contains('name','hello2');
        $resF = $collection -> contains('name','hello');
        dd($resO,$resT,$resTh,$resF);
    }

    /**
     * 一人得道
     */
    public function myContains3(){
        $collection = collect(['name' => 'hello','age' => 20,'height' => 100]);
        //用来判断键名/键值是否有存在满足某个条件,一有满足,结果返回true,若无一元素满足,返回false

        //所有键值对皆处理过后仍然没有结果时返回false
        $isArr = $collection->contains(function($item,$key){
            var_dump($item);
            if($item < 90 && $item > 10){
                //return 1;
                return true;
            }else{
                //迭代数组,若闭包函数返回结果bool值为true (例如返回 1 ),则终止迭代数组
                //return 0;
                return false;
            }
        });
        dd($collection,$isArr);
    }

    //返回集合中所有项的总数
    public function myCount(){
        return $this->collection->count();
    }

    //将集合和另一个集合或原生PHP数组以基于值的方式作比较，这个方法会返回存在于原来集合而不存在于给定集合的值
    public function myDiff(){
        $diff = $this->collection->diff([1,3]);
        dd($diff);
    }

    //会基于犍对集合和另一个集合或原生PHP数组进行比较。该方法会返回存在于原来集合而不存在于给定集合的键值对
    public function myDiffKeys(){
        //键名的相消
        $collectionO = collect([
            'one' => 40,
            'two' => 12,
            'three' => 20,
            'four' => 50
        ]);
        $collectionT = collect([
            'one' => 100,
            'two' => 25,
            'six' => 90
        ]);
        $diffKey = $collectionO->diffKeys($collectionT);
        return $diffKey->all();
    }

    /**
     * 迭代集合中的数据项并传递每个数据项到给定回调
     * 结果如何都返回对象本身
     */
    public function myEach(){
        $res = $this->collection->each(function($item,$key){
            var_dump($item);
            if($key == 2){
                //终止对数据项的迭代，可以从回调返回 false
                //终止条件判断是 '=== false'
                return false;
            }
            //不会影响集合本
            return $item = 0;
        });
        var_dump($res);
        echo '_________';
        //只处理第一维
        collect([
            [
                'name' => 'haha'
            ],[
                'name' => 'hehe'
            ]
        ])->each(function($item,$key){
            var_dump($item);
        });
        return 'end';
    }

    /**
     * 用于验证集合的所有元素能够通过给定的真理测试
     * 返回bool值
     * 一颗老鼠屎
     * (一个不符合(返回值的bool代表为false),则终止迭代,返回false
     *
     * every()有其它用法
     *
     * 注: every($callback)和contains($callback) each($callback)区别
     * 1.every()迭代数组检测有一为false(或bool值为false)终止迭代,返回false,要全部满足
     * 2.contains()迭代数组,一有true(或bool值为true)终止迭代,返回true,只要有一满足
     * 3.each()迭代数组,闭包结果一有全等的false结果,终止迭代,返回对象自身
     */
    public function myEvery(){
        //迭代了一次 返回false终止迭代
        $this->collection->every(function($item,$key){
            var_dump($item);
            return $item > 1;
        });
        echo '---------------------';
        //迭代了四次 只处理到第一维
        collect([[1,2],3,4,5])->every(function($item,$key){
            var_dump($item,$key);
            return $item > 1;
        });
        //        true ,  false
        var_dump([] > 100,0 > 100);
        $resO = $this->collection->every(0,'=',1);
        $resT = $this->collection->every(['1','2',3],'=',2);
        var_dump($resO,$resT);
    }

    /**
     * 返回集合中除了指定键的所有集合项
     */
    public function myExcept(){
        $res = $this->collection->except(0);
        dd($this->collection,$res);
    }

    /**
     * 通过给定回调过滤集合，只有通过给定真理测试的数据项才会保留下来
     */
    public function myFilter(){
        $res = $this->collection->filter(function($item,$key){
            return $item > 2;
        });
        $resT = $this->collection->filter();
        dd($this->collection,$res,$resT);
    }

    /**
     * 通过给定回调过滤集合，通过给定真理测试的数据项才会剔除
     */
    public function  myReject(){
        $res = $this->collection->reject(function($item,$key){
            return $item > 2;
        });
        //和filter不一样 不能缺省参数
        //$resT = $this->collection->reject();
        dd($this->collection,$res);
    }

    /**
     * 返回通过真理测试集合的第一个元素
     * 注:last()同样适用方法
     */
    public function myFirst(){
        $res = $this->collection->first();
        $resT = $this->collection->first(function($item,$key){
            return $item > 1;
        });
        dd($res,$resT);//1 2 不是[0=>1] [0=>2]
    }

    /**
     * 会迭代集合并传递每个值到给定回调，该回调可以自由编辑数据项并将其返回，最后形成一个经过编辑的新集合。然后，这个数组在层级维度被扁平化
     * @return static
     */
    public function myFlatMap(){
        $collection = collect([
            ['name' => 'sally','loaction' => 'xia men'],
            ['school' => 'Arkansas'],
            ['age' => 28]
        ]);
        //5.1没有
        $falttened = $collection->flatMap(function ($item){
            return array_map('ucfirst',$item);
        });
        return $falttened;
    }

    /**
     * 将多维度的集合变成一维的
     */
    public function myFlatten(){
        $collection = collect(['name' => 'taylor','langue' => ['php','javascript']]);
        $flattened = $collection->flatten();
        $collectionT = collect([
            'Apple' => [
                ['name' => 'iPhone 6S', 'brand' => 'Apple'],
            ],
            'Samsung' => [
                ['name' => 'Galaxy S7', 'brand' => 'Samsung']
            ],
        ]);
        //可以选择性传入深度参数 允许你严格设置被扁平化的数组层级
        //涉及到的维度键名会变索引,键名未涉及的不变
        $products = $collectionT->flatten(2);
        //缺省 全部扁平化
        $productsT = $collectionT->flatten();
        $productsTh = $collectionT->flatten(1);

        dd($flattened->all(),$products->all(),$productsT->all(),$productsTh->all());
    }

    /**
     * 将集合的键值做交换
     */
    public function myFlip(){
        $collection = collect(['name' => 'taylor', 'framework' => 'laravel']);

        $flipped = $collection->flip();

        dd($flipped->all());
    }

    /**
     * 通过键从集合中移除数据项
     * 注：不同于大多数其他的集合方法，forget 不返回新的修改过的集合；它只修改所调用的集合。
     */
    public function myForget(){
        $collection = collect(['name' => 'taylor', 'framework' => 'laravel']);

        $collection->forget('name');

        dd($collection->all());
    }

    /**
     * 返回新的包含给定页数数据项的集合。该方法接收页码数作为第一个参数，每页显示数据项数作为第二个参数
     */
    public function myForPage(){
        $collection = collect([1, 2, 3, 4, 5, 6, 7, 8, 9]);

        $chunk = $collection->forPage(2, 3);

        dd($chunk->all());
    }

    /**
     * 返回给定键的数据项，如果对应键不存在，返回null
     */
    public function myGet(){
        $collection = collect(['name' => 'taylor', 'framework' => 'laravel']);

        $value = $collection->get('name');
        $valueT = $collection->get('hello');
        $valueTh = $collection->get('hello','123');
        $valueF = $collection->get('world',function(){
            return '不存在,会调用闭包函数,返回结果';
        });
        $valueFi = $collection->get('framework',function(){
            return 'no';
        });
        dd($value,$valueT,$valueTh,$valueF,$valueFi);
    }

    /**
     * 通过给定键分组集合数据项
     */
    public function myGroupBy(){
        $collection = collect([
            ['account_id' => 'account-x10', 'product' => 'Chair'],
            ['account_id' => 'account-x10', 'product' => 'Bookcase'],
            ['account_id' => 'account-x11', 'product' => 'Desk'],
            ['account_id' => 'accccct-x11', 'product' => 'Desk'],
        ]);

        $grouped = $collection->groupBy('account_id');
        //可以传递一个回调，回调应该返回分组后的值
        $groupedT = $collection->groupBy(function($item,$key){
            //根据结果
            //return 1;
            return substr($item['account_id'],-3);
        });

        dd($grouped->toArray(),$groupedT->toArray());
    }

    /**
     * 判断给定键是否在集合中存在
     */
    public function myHas(){
        $collection = collect(['account_id' => 1, 'product' => 'Desk']);

        $res = $collection->has('email');

        //测试能涉及的维度
        $collectionT = collect([
            'Apple' => [
                ['name' => 'iPhone 6S', 'brand' => 'Apple'],
            ],
            'Samsung' => [
                ['name' => 'Galaxy S7', 'brand' => 'Samsung']
            ],
        ]);
        //false 只能检测到最外维
        $resT = $collectionT->has('brand');
        dd($res,$resT);
    }

    /**
     * 连接集合中的数据项。其参数取决于集合中数据项的类型。如果集合包含数组或对象，应该传递你想要连接的属性键，以及你想要放在值之间的 “粘合”字符串
     */
    public function myImplode(){
        //这是二维的
        $collection = collect([
            ['account_id' => 1, 'product' => 'Desk'],
            ['account_id' => 2, 'product' => 'Chair'],
        ]);

        $res = $collection->implode('product', ', ');

        $resT = $collection->implode(', ');

        //如果集合包含简单的字符串或数值，只需要传递“粘合”字符串作为唯一参数到该方法
        $resTh = collect(['account_id' => 1, 'product' => 'Desk'])->implode(',');

        dd($res,$resT,$resTh);
    }

    /**
     * 返回两个集合的交集，结果集合将保留 原来集合 的键
     */
    public function myIntersect(){
        //注:比较的键值,不是键名,保留的键名取前者
        $collection = collect(['Desk', 'Sofa','3th'=> 'Chair']);

        $intersect = $collection->intersect(['3th'=>'Desk', 'Chair', 'Bookcase']);

        $res = $intersect->all();

        dd($res);
    }

    /**
     * 如果集合为空的话 isEmpty 方法返回 true；否则返回 false
     */
    public function myIsEmpty(){
        $res = collect([])->isEmpty();
        dd($res);
    }

    /**
     * 指定键的值作为集合的键，如果多个数据项拥有同一个键，只有最后一个会出现在新集合里面
     */
    public function myKeyBy(){
        $collection = collect([
            ['product_id' => 'prod-100', 'name' => 'desk'],
            ['product_id' => 'prod-200', 'name' => 'chair'],
        ]);

        $keyed = $collection->keyBy('product_id');
        //传递自己的回调到该方法，该回调将会返回经过处理的键的值作为新的集合键
        $keyedT = $collection->keyBy(function ($item) {
            return strtoupper($item['product_id'].'0');
        });

        $res = $keyed->all();
        dd($res,$keyedT->all());
    }

    /**
     * 返回所有集合的键
     */
    public function keys(){
        $collection = collect([
            'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
            'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
        ]);

        $keys = $collection->keys();

        dd($keys->all());
    }

    /**
     * 方法遍历集合并传递每个值给给定回调。该回调可以修改数据项并返回，从而生成一个新的经过修改的集合
     * @return static
     */
    public function myMap(){
        //集合方法

        //查源码:第一个参数键值,第二个参数键名
        return $this->collection->map(function($item,$key){
            var_dump($item);//键值
            var_dump($key);//键名
            return $item;
        });
    }

    /**
     * 对集合进行迭代并传递每个值到给定回调，该回调会返回包含键值对的关联数组
     */
    public function myMapWithKeys(){
        $collection = collect([
            [
                'name' => 'John',
                'department' => 'Sales',
                'email' => 'john@example.com'
            ],
            [
                'name' => 'Jane',
                'department' => 'Marketing',
                'email' => 'jane@example.com'
            ]
        ]);

        $keyed = $collection->mapWithKeys(function ($item) {
            return [$item['email'] => $item['name']];
        });

        dd($keyed->all());

    }

    /**
     * 返回集合中给定键的最大值
     * 注:min()同
     */
    public function myMax(){
        $max = collect([['foo' => 10], ['foo' => 20]])->max('foo');

// 20

        $maxT = collect([1, 2, 3, 4, 5])->max();

// 5
        dd($max,$maxT);
    }

    /**
     * 合并给定数组到集合。该数组中的任何字符串键匹配集合中的字符串键的将会重写集合中的值
     * 如果给定数组的键是数字，数组的值将会附加到集合后面
     */
    public function myMerge(){
        $collection = collect(['product_id' => 1, 'name' => 'Desk']);

        $merged = $collection->merge(['price' => 100, 'discount' => false]);

        $res = $merged->all();
        dd($res);
    }

    /**
     * 组合集合中第n-th个元素创建一个新的集合
     * 从第0开始,隔着n取一个数
     */
    public  function myNth(){
        $collection = collect(['a', 'b', 'c', 'd', 'e', 'f']);

        //可以传递一个offset（偏移位置）作为第二个参数


        dd($collection->nth(2),$collection->nth(2,1));

    }

    /**
     * 返回集合中指定键的集合项
     */
    public function myOnly(){
        $collection = collect(['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]);

        $filtered = $collection->only(['product_id', 'name']);

        $res = $filtered->all();
        dd($res);
    }

    /**
     * partition方法可以和PHP函数list一起使用，从而将通过真理测试和没通过的分割开来
     */
    public function myPartition(){
        $collection = collect([1, 2, 3, 4, 5, 6]);

        list($underThree, $aboveThree) = $collection->partition(function ($i) {
            return $i < 3;
        });
        dd($underThree,$aboveThree);
    }

    /**
     * 传递集合到给定回调并返回结果
     */
    public function myPipe(){
        $collection = collect([1, 2, 3]);

        $piped = $collection->pipe(function ($collection) {
            return $collection->sum();
        });
        dd($piped);
    }

    /**
     * 为给定键获取所有集合值
     */
    public function myPluck(){
        $collection = collect([
            ['product_id' => 'prod-100', 'name' => 'Desk'],
            ['product_id' => 'prod-200', 'name' => 'Chair'],
        ]);

        $plucked = $collection->pluck('name');

        //可以指定你想要结果集合如何设置键：
        $pluckedT = $collection->pluck('name', 'product_id');

        $resT = $pluckedT->all();
        $res = $plucked->all();
        dd($res,$resT);
    }

    /**
     * 移除并返回集合中最后面的数据项
     */
    public function myPop(){
        $collection = collect([1, 2, 3, 4, 5]);

        $collection->pop();

        dd($collection->all());
    }

    /**
     * 添加数据项到集合开头
     */
    public  function myPrepend(){
        $collection = collect([1, 2, 3, 4, 5]);

        $collection->prepend(0);

        //传递第二个参数到该方法用于设置前置项的键

        $collectionT = collect(['one' => 1, 'two' => 2]);

        $collectionT->prepend(0, 'zero');
        dd($collection->all(),$collectionT->all());
    }
}
